#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <pthread.h>

// 设计方的视角
//typedef std::function<void()> func_t;
template<class T>
using func_t = std::function<void(T)>;//返回值为void，参数为T

template<class T>
class Thread
{
public:
    Thread(const std::string &threadname, func_t<T> func, T data)
    :_tid(0), _threadname(threadname), _isrunning(false), _func(func), _data(data)
    {}

    static void *ThreadRoutine(void *args) // 不加static：类内方法，默认第一个参数是Thread* this，而pthread_create要求第三个参数的函数参数为void*
    {//所以会报错。解决方案，可以直接将这个函数放到类外就可以解决，也可以加上static
        // (void)args; // 仅仅是为了防止编译器有告警
        Thread *ts = static_cast<Thread *>(args);

        ts->_func(ts->_data);//加上static之后就无法访问类内私有成员了，所以要在pthread_create传入this，在上面强转一下

        return nullptr;
    }

    bool Start()
    {
        int n = pthread_create(&_tid, nullptr, ThreadRoutine, this/*?*/);
        //不管怎么封装，都得创建线程，得用到pthread.h中的pthread_create
        if(n == 0) //创建成功返回0
        {
            _isrunning = true;
            return true;
        }
        else return false;
    }
    bool Join()
    {
        if(!_isrunning) return true;//线程必须先运行才可以join
        int n = pthread_join(_tid, nullptr);
        if(n == 0)//join成功
        {
            _isrunning = false;
            return true;
        }
        return false;
    }
    std::string ThreadName()
    {
        return _threadname;
    }
    bool IsRunning()
    {
        return _isrunning;
    }
    ~Thread()
    {}
private:
    pthread_t _tid;//线程id
    std::string _threadname;//线程名字
    bool _isrunning;//线程是否运行
    func_t<T> _func;//回调函数
    T _data;
};
